﻿using Devil;
using System;
using UnityEngine;
#if VISUAL_SCRIPTING
using Unity.VisualScripting;
#endif

namespace GameToolkit
{
    [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
    public class AssetPathAttribute : PropertyAttribute
    {
        public Type AssetType { get; set; }
        public bool ShortName { get; set; }

        public string Folder { get; set; }

        public AssetPathAttribute() : base()
        {
            AssetType = typeof(UnityEngine.Object);
        }

        public AssetPathAttribute(Type assetType) : base()
        {
            AssetType = assetType;
        }
    }

    [System.Serializable]
#if VISUAL_SCRIPTING
    [Inspectable]
#endif
    public struct AssetAddress : IEquatable<AssetAddress>
    {
#if UNITY_EDITOR
        [SerializeField] string guid;
#endif
        [SerializeField]
//#if VISUAL_SCRIPTING
//        [Inspectable]
//#endif
        string path;
        [SerializeField]
//#if VISUAL_SCRIPTING
//        [Inspectable]
//#endif
        bool variant;

        public AssetAddress(string path)
        {
            this.path = path;
#if UNITY_EDITOR
            this.guid = "";
#endif
            this.variant = false;
        }

        public bool IsNull
        {
            get
            {
#if UNITY_EDITOR
                return string.IsNullOrEmpty(path) && string.IsNullOrWhiteSpace(guid);
#else
                return string.IsNullOrEmpty(path);
#endif
            }
        }

        public IAssetCache<T> GetAssetAsync<T>() where T : UnityEngine.Object
        {
            var file = ToString();
            if (string.IsNullOrEmpty(file))
                return null;
            else
                return AssetsUtil.GetAssetAsync<T>(file);
        }

        public bool Equals(AssetAddress other)
        {
#if UNITY_EDITOR
            return guid != null && guid.Equals(other.guid);
#else
            return path != null && path.Equals(other.path);
#endif
        }

        public override string ToString()
        {
#if UNITY_EDITOR
            if (!string.IsNullOrEmpty(guid) && ParallelUnity.IsMainThread)
            {
                var str = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
                if (!str.Equals(path))
                    Debug.LogErrorFormat("资源 \"{0}\" 与 guid \"{1}\" 不匹配", path, guid);
                var grp = variant ? AssetsUtil.VariantsForEditor.GetVariantGroup(EVariantGroupQuery.AssetPath, str) : null;
                if (grp != null)
                    return grp.GetAssetAddress(str);// ABVariant.GetAssetPathWithOutVariant(str);
                else
                    return str;
            }
#endif
            var grp2 = variant ? AssetsUtil.UtilInstance?.Variants?.GetVariantGroup(EVariantGroupQuery.AssetPath, path) : null;
            if (variant)
                return grp2.GetAssetAddress(path);
            else
                return path;
        }

        public string ToString(UnityEngine.Object context)
        {
#if UNITY_EDITOR
            if (!string.IsNullOrEmpty(guid))
            {
                var str = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
                if (!str.Equals(path))
                    Debug.LogErrorFormat(context, "资源 \"{0}\" 与 guid \"{1}\" 不匹配", path, guid);
                var grp = variant ? AssetsUtil.VariantsForEditor.GetVariantGroup(EVariantGroupQuery.AssetPath, str) : null;
                if (grp != null)
                    return grp.GetAssetAddress(str);// ABVariant.GetAssetPathWithOutVariant(str);
                else
                    return str;
            }
#endif
            var grp2 = variant ? AssetsUtil.UtilInstance?.Variants?.GetVariantGroup(EVariantGroupQuery.AssetPath, path) : null;
            if (variant)
                return grp2.GetAssetAddress(path);
            else
                return path;
        }

        public static implicit operator string(AssetAddress add)
        {
            return add.ToString();
        }

        public static explicit operator AssetAddress(UnityEngine.Object asset)
        {
            AssetAddress add = default;
#if UNITY_EDITOR
            add.path = UnityEditor.AssetDatabase.GetAssetPath(asset);
            add.guid = string.IsNullOrEmpty(add.path) ? "" : UnityEditor.AssetDatabase.AssetPathToGUID(add.path);
            add.variant = AssetsUtil.VariantsForEditor.GetVariantGroup(EVariantGroupQuery.AssetPath, add.path) != null;
            //MakeAB.AutoVariantsPattern != null && MakeAB.AutoVariantsPattern.IsMatch(add.path);
#else
            Debug.LogError("Can't convert an asset to AssetPath (release mode)");       
#endif
            return add;
        }
    }
}